import 'package:xbaistack/widget/my_text_field.dart';
import 'package:flutter/material.dart';
import 'package:xbaistack/common/gen.dart';
import 'click_able.dart';
import 'my_switcher.dart';

class GroupSetting extends StatelessWidget {
  // 收集所有子项
  final List<Item> children;
  final double vSpacing;
  final double hSpacing;
  final EdgeInsets boxInsets;
  GroupSetting({
    super.key,
    required this.children,
    this.vSpacing = 8,
    this.hSpacing = 8,
  }) : boxInsets = EdgeInsets.symmetric(
         vertical: vSpacing,
         horizontal: hSpacing,
       );

  @override
  Widget build(BuildContext context) {
    return SizedBox.expand(
      child: SingleChildScrollView(
        child: ListView.builder(
          shrinkWrap: true,
          // 去除重复边界
          addRepaintBoundaries: false,
          // 禁用 ListView 的滚动效果
          // 这样一来子项无论有多少，都会直接显示出来
          // 然后由外部的 SingleChildScrollView 负责滚动
          physics: const NeverScrollableScrollPhysics(),
          // ListView 子组件的生成数量
          // 如果不设置的话，滚动时会无限生成子项
          itemCount: children.length,
          // 动态创建子项内容，通过 Item 抽象类来决定具体的内容
          itemBuilder: (context, index) {
            Item item = children[index];
            Widget widget = item.build(this, context);
            return widget;
          },
        ),
      ),
    );
  }
}

abstract class Item {
  Widget build(GroupSetting widget, BuildContext context);
  static Item customize(Widget child) => _ItemCustomize(child);
  static Item spacer([double space = 10]) => _ItemSpacer(space);
  static Item leading(String text) => _ItemLeading(text);
  static Item select({
    Widget? icon,
    required String title,
    String? subtitle,
    Widget? center,
    required bool value,
    bool? disabled,
    ValueChanged<bool>? onChanged,
  }) {
    return _ItemSelect(
      icon: icon,
      title: title,
      subtitle: subtitle,
      // center: center,
      value: value,
      onChanged: onChanged,
      // disabled: disabled,
    );
  }

  static Item text({
    Widget? icon,
    required String title,
    String? subtitle,
    String? description,
    VoidCallback? onTap,
    Type? goto,
  }) => _ItemText(
    title: title,
    subtitle: subtitle,
    icon: icon,
    description: description,
    onTap: onTap,
    goto: goto,
  );
  static Item switcher({
    Widget? icon,
    required String title,
    String? subtitle,
    String? description,
    bool value = false,
    ValueChanged<bool>? onChanged,
  }) => _ItemSwitcher(
    title: title,
    subtitle: subtitle,
    icon: icon,
    description: description,
    onChanged: onChanged,
    value: value,
  );
  static Item input({
    required String title,
    String? value,
    ValueChanged<String>? onChanged,
  }) => _ItemInput(title: title, onChanged: onChanged, value: value);
}

class _ItemCustomize extends Item {
  final Widget child;

  _ItemCustomize(this.child);

  @override
  Widget build(GroupSetting widget, BuildContext context) => child;
}

class _ItemSpacer extends Item {
  final double space;

  _ItemSpacer(this.space);

  @override
  Widget build(GroupSetting widget, BuildContext context) {
    return SizedBox(height: space);
  }
}

class _ItemLeading extends Item {
  final String leading;

  _ItemLeading(this.leading);

  @override
  Widget build(GroupSetting widget, BuildContext context) {
    return Padding(
      // symmetric：用于设置组件的垂直、水平间距
      // 属于组合式设置方法的一种
      padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
      // 主要内容就是 Text 了，用于显示标签文本
      // 注意颜色和字体大小
      child: Text(
        leading,
        style: const TextStyle(color: Colors.grey, fontSize: 14),
      ),
    );
  }
}

class _ItemText extends _ItemCommon {
  _ItemText({
    super.icon,
    required super.title,
    super.subtitle,
    super.description,
    super.onTap,
    super.goto,
    super.arrow,
  });
}

abstract class _ItemCommon extends Item {
  // 图标（接受 Image | Icon 两个种类，不限定具体使用什么）
  final Widget? icon;

  // 主标题
  final String title;

  // 子标题
  final String? subtitle;

  // 描述文本
  final String? description;

  // 是否显示右箭头（表示可以跳转下一级操作）
  final bool arrow;

  // onTap | goto 二选一
  final VoidCallback? onTap;

  // 一般设置项都是仅跳转，所以添加一个快捷方式
  // 这里需要注意哈，这种方式需要结合前几期的【统一路由】来看
  // 否则你可能会云里雾里的
  final Type? goto;

  // 这个方法留给子类去实现，具体怎样实现，这里不用关心
  Widget? ending(GroupSetting widget, BuildContext context) => null;
  Widget? buildInput(GroupSetting widget, BuildContext context) => null;

  _ItemCommon({
    this.icon,
    required this.title,
    this.subtitle,
    this.description,
    this.arrow = true, // 默认显示这个右箭头，不需要的话设置为 false 就可以了
    this.onTap, // 用于处理点击事件的回调
    this.goto, // 当内容项仅跳转页面时，可以使用此属性设置路由跳转地址
  }) : assert(icon == null || icon is Image || icon is Icon),
       assert(onTap == null || goto == null);

  @override
  Widget build(GroupSetting widget, BuildContext context) {
    // 获取统一主题数据
    // 可以用它来复制默认主题样式
    final theme = Theme.of(context);

    // Row 的子项列表，这样写好处是便于我们在逻辑分支中添加组件
    List<Widget> items = <Widget>[];

    // 构建图标
    // 这里的图标为了不限制死，支持两种写法
    // 一是 Image 图片资源，但是为了防止外部设置图片尺寸，所以这里只使用图片源而固定宽高
    // 二是 Icon 字体图标，这样不仅可以显示字体图片也支持图片
    Widget? imageIcon;
    if (icon != null) {
      if (icon is Image) {
        imageIcon = Image(image: (icon as Image).image, width: 32, height: 32);
      } else if (icon is Icon) {
        imageIcon = IconTheme(
          data: theme.iconTheme.copyWith(size: 32),
          child: icon as Icon,
        );
      }
    }
    // 如果上面对 imageIcon 进行了初始化，那说明此变量不为空
    // 直接将其添加到 items 中即可
    if (imageIcon != null) {
      items.add(Container(width: 50, child: imageIcon));
    }

    // 主标题
    // 默认我们认为没有子标题，所以 title 就成了唯一的内容
    // 因此可以直接使用 Text 来实例化 caption 对象
    Widget caption = Text(
      title,
      style: const TextStyle(fontSize: 14),
      strutStyle: const StrutStyle(leading: 0, forceStrutHeight: true),
    );

    // 子标题
    // 这里当判断子标题不为空（或者空字符串）时
    // 我们将其改变为 Column 上下布局的方式，就可以将子标题显示在 title 下方了
    if (subtitle?.isNotEmpty ?? false) {
      caption = Column(
        mainAxisSize: MainAxisSize.max,
        // 此属性表示在纵向方向上靠左排列
        // CrossAxisAlignment.end 则靠右排列
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          caption,
          Text(
            subtitle!,
            style: const TextStyle(fontSize: 12, color: Colors.grey),
            strutStyle: const StrutStyle(leading: 0, forceStrutHeight: true),
          ),
        ],
      );
    }

    // 这里是为了防止没有传递任何图标，因此缺少一个空位
    // 那么标题组件就会紧挨着左侧，一点间隙都没有
    // 所以当没有图标的时候，给标题栏左侧设置一个间距
    if (imageIcon == null) {
      caption = Padding(
        padding: widget.boxInsets.copyWith(left: widget.boxInsets.left),
        child: caption,
      );
    }

    // 这里由于标题栏是真个内容的主体
    // 所以将其使用 Expanded 包裹起来，撑满整个 Row 的剩余空间
    items.add(Expanded(child: caption));

    // 描述文本
    if (description?.isNotEmpty ?? false) {
      items.add(
        Text(
          description!,
          style: const TextStyle(fontSize: 14, color: Colors.grey),
          strutStyle: const StrutStyle(leading: 0, forceStrutHeight: true),
        ),
      );
    }

    // 添加尾部小组件（这个留给具体的子类去实现，公共类中不作处理）
    final endWidget = ending(widget, context);
    if (endWidget != null) {
      items.add(endWidget);
    }

    // 显示右箭头
    if (arrow) {
      items.add(
        Padding(
          padding: widget.boxInsets,
          child: const Icon(
            Icons.arrow_forward_ios,
            size: 18,
            color: Colors.grey,
          ),
        ),
      );
    }
    final iptWidget = buildInput(widget, context);
    if (iptWidget != null) {
      return Container(
        decoration: BoxDecoration(color: Colors.white),
        padding: widget.boxInsets.copyWith(
          right: widget.boxInsets.left * 2,
          top: widget.boxInsets.top / 2,
          bottom: widget.boxInsets.top / 2,
        ),
        child: Row(
          mainAxisSize: MainAxisSize.max,
          children: [...items, iptWidget],
        ),
      );
    }
    // Clickable 一个具有点击效果并且能处理点击事件的自定义组件
    // 贴在文末的，待会儿你可以去看看~
    // context.routeTo(goto!) 如果报错请看我【统一路由】那期
    return Clickable(
      onTap: goto == null ? onTap : () => context.routeTo(goto!),
      backgroundColor: Colors.white,
      padding: widget.boxInsets,
      border: const Border(bottom: BorderSide(color: Colors.grey, width: 0.1)),
      child: Row(mainAxisSize: MainAxisSize.max, children: items),
    );
  }
}

class _ItemInput extends _ItemCommon {
  final String? value;
  final ValueChanged<String>? onChanged;

  _ItemInput({this.value, required super.title, this.onChanged})
    : super(arrow: false); // a rrow 为 false 即不显示右侧箭头

  @override
  Widget? buildInput(GroupSetting widget, BuildContext context) {
    return Expanded(
      child: MyTextField(onChanged: onChanged, value: value),
      flex: 2,
    );
  }
}

class _ItemSwitcher extends _ItemCommon {
  // 状态开关的初始值（ture：打开，false：关闭）
  final bool value;
  // 状态切换回调
  final void Function(bool)? onChanged;

  _ItemSwitcher({
    super.icon,
    required super.title,
    super.subtitle,
    super.description,
    this.value = false,
    this.onChanged,
  }) : super(arrow: false); // a rrow 为 false 即不显示右侧箭头

  @override
  Widget? ending(GroupSetting widget, BuildContext context) {
    return Padding(
      padding: EdgeInsets.only(right: widget.boxInsets.horizontal),
      // Switcher 是我基于 flutter_switch 组件进行二次封装的一个组件
      // 贴在文末的，放在前面影响整体逻辑，望知晓~
      child: MySwitcher(value: value, onChanged: onChanged),
    );
  }
}

class _ItemNormal extends Item {
  final Widget? icon;

  // 主标题
  final String title;

  // 子标题
  final String? subtitle;

  // 描述文本
  final String? value;
  // onTap | goto 二选一
  final VoidCallback? onTap;

  // 一般设置项都是仅跳转，所以添加一个快捷方式
  // 这里需要注意哈，这种方式需要结合前几期的【统一路由】来看
  // 否则你可能会云里雾里的
  final Type? goto;
  final bool? arrow;
  final bool? clickable;
  final bool? limitEndingWidth;

  _ItemNormal({
    this.onTap,
    this.goto,
    this.icon,
    this.arrow,
    this.limitEndingWidth,
    this.clickable,
    required this.title,
    this.subtitle,
    this.value,
  });

  /// 本期新添加的方法
  /// 主要是为了聚合逻辑处理，免得你们看的云里雾里的
  void onTapHandler(BuildContext context) {
    if (onTap == null) {
      if (goto != null) {
        context.routeTo(goto!);
      }
    } else {
      onTap!.call();
    }
  }

  Widget? buildEnding(GroupSetting widget, BuildContext context) => null;

  @override
  Widget build(GroupSetting widget, BuildContext context) {
    final endWidget = buildEnding(widget, context);
    return Clickable(
      onTap: () => onTapHandler(context),
      child: Container(
        padding: const EdgeInsets.all(14),
        decoration: BoxDecoration(
          color: Colors.white,
          border: Border(bottom: BorderSide(color: Colors.grey, width: 0.1)),
        ),
        child: Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(title, style: TextStyle(fontSize: 16)),
            endWidget ?? SizedBox.shrink(),
          ],
        ),
      ),
    );
  }
}

class _ItemSelect extends _ItemNormal {
  bool _value;
  final ValueChanged<bool>? onChanged;
  _ItemSelect({
    super.icon,
    required super.title,
    super.subtitle,
    required bool value,
    this.onChanged,
  }) : _value = value,
       super(clickable: true, limitEndingWidth: false, arrow: false);

  // 我记得那一期的内容好像没有写这个函数？？？
  @override
  void onTapHandler(BuildContext context) {
    onChanged?.call(_value = !_value);
  }

  @override
  Widget? buildEnding(GroupSetting widget, BuildContext context) {
    return _value
        ? const Icon(Icons.check, color: Colors.blueAccent, size: 24)
        : null;
  }
}
